/*
 * SHOPTNT 版权所有。
 * 未经许可，您不得使用此文件。
 * 官方地址：www.shoptnt.cn
 */
package cn.shoptnt.service.security;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.UpdateChainWrapper;
import cn.shoptnt.client.system.SettingClient;
import cn.shoptnt.client.system.SmsClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import cn.shoptnt.framework.util.DateUtil;
import cn.shoptnt.framework.util.JsonUtil;
import cn.shoptnt.framework.util.StringUtil;
import cn.shoptnt.mapper.security.FalsifyRecordMapper;
import cn.shoptnt.mapper.security.SecurityModuleMapper;
import cn.shoptnt.model.base.SettingGroup;
import cn.shoptnt.model.base.vo.SmsSendVO;
import cn.shoptnt.model.security.ScanResult;
import cn.shoptnt.model.security.ScanSateEnum;
import cn.shoptnt.model.security.SecurityModuleEnum;
import cn.shoptnt.model.system.vo.AccountSetting;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;

/**
 * 扫描任务基类
 * 提供基本的扫描循环能力：
 * 1、循环过程中从配置文件读取扫描持续时长
 * 2、扫描结果处理：发短消息
 * 3、更新模块扫描状态
 * @author 妙贤
 * @version 1.0
 * @data 2021/11/20 16:38
 **/
public abstract class BaseSignScanTask<T> implements SignScanTask {

    protected Logger logger = LoggerFactory.getLogger(this.getClass());

    protected Long pageSize =10L;

    @Autowired
    protected FalsifyRecordMapper falsifyRecordMapper;

    @Autowired
    private SecurityModuleMapper securityModuleMapper;

    @Autowired
    private SmsClient smsClient;

    @Autowired
    private SettingClient settingClient;

    @Override
    @Transactional(value = "tradeTransactionManager", propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
    @Async
    public void scan(String rounds,String moduleName) throws IllegalAccessException {

        logger.debug("开始扫描"+moduleName+",轮次:[" + rounds + "]...");

        Long endTime = getScanEndTime();

        Long orderTimes = 1L;
        //标识是否存在失败的验签数据：默认不存在
        boolean existFail = false;
        while (true) {
            logger.debug("扫描第[" + orderTimes + "]...");
            Long now = DateUtil.getDateline();
            if (now > endTime) {
                break;
            }

            //扫描商品
            ScanResult scanResult = scanModule(rounds);
            //有一轮失败，就失败
            if (!scanResult.isSuccess()) {
                existFail = true;
            }
            if (scanResult.isComplete()) {
                //标记为本轮次扫描完成
                new UpdateChainWrapper<>(securityModuleMapper).set("state", ScanSateEnum.finished.name()).eq("module_name",moduleName).update();
                break;
            }
            orderTimes++;
        }


        if (existFail) {
            //给管理员发送签名校验失败消息
            sendFailMessage(moduleName);

        }

        logger.debug("扫描"+moduleName+"轮次:[" + rounds + "]完成");

    }

    /**
     * 获取本次扫描结束时间
     *
     * @return
     */
    protected Long getScanEndTime() {
        //获取扫描配置
        String accountSettingJson = settingClient.get( SettingGroup.ACCOUNT);
        AccountSetting accountSetting = JsonUtil.jsonToObject(accountSettingJson, AccountSetting.class);
        Integer scanTime = accountSetting.getScanningTime();

        //默认一小时
        if (scanTime == null) {
            scanTime=1;
        }
        //转为秒
        scanTime = scanTime*60*60;
        return DateUtil.getDateline() + scanTime;
    }

    protected QueryWrapper<T> createWrapper(String rounds) {
        QueryWrapper<T> queryWrapper = new QueryWrapper();

        //状态是校验成功的
        queryWrapper.eq("sign_result", 1);

        //本轮扫描未完成的
        queryWrapper.and(qw->qw.ne("scan_rounds", rounds).or().isNull("scan_rounds") ) ;
        return queryWrapper;
    }

    /**
     * 调用系统的短信发送能力接口发送短信
     * @param moduleName
     */
    protected void sendFailMessage(String moduleName) {
        moduleName = SecurityModuleEnum.valueOf(moduleName).getModuleName();
        String message = moduleName + "模块发现数据被篡改，发现时间：" + DateUtil.toString(new Date(), "yyyy-MM-dd HH:mm:ss");
        String accountSettingJson = settingClient.get( SettingGroup.ACCOUNT);
        AccountSetting accountSetting = JsonUtil.jsonToObject(accountSettingJson, AccountSetting.class);
        if (accountSetting!=null&& !StringUtil.isEmpty(accountSetting.getMobile())){
            logger.debug("发送数据被篡改报警短信,接收手机号:"+accountSetting.getMobile()+",消息内容："+message);
            SmsSendVO smsSendVO = new SmsSendVO();
            smsSendVO.setMobile(accountSetting.getMobile());
            smsSendVO.setContent(message);
            smsClient.send(smsSendVO);
        }
    }

    protected abstract ScanResult scanModule(String rounds)throws IllegalAccessException;

}
